package com.punai.dataanalysis.srlib.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.multi.ListValueMap;
import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.PageInfo;
import com.punai.common.core.domain.CommonConstants;
import com.punai.common.core.page.TableDataInfo;
import com.punai.common.core.text.Convert;
import com.punai.common.utils.DateUtil;
import com.punai.common.utils.NumberUtil;
import com.punai.common.utils.PageUtils;
import com.punai.common.utils.SecurityUtils;
import com.punai.config.domain.ConfigInventoryChapter;
import com.punai.config.domain.ConfigInventoryLib;
import com.punai.config.mapper.ConfigInventoryChapterMapper;
import com.punai.config.mapper.ConfigInventoryLibMapper;
import com.punai.dataanalysis.srlib.bo.GbInventoryPriceBo;
import com.punai.dataanalysis.srlib.bo.InventoryPriceBo;
import com.punai.dataanalysis.srlib.mapper.InventoryPriceMapper;
import com.punai.dataanalysis.srlib.service.GbInventoryPriceService;
import com.punai.dataanalysis.srlib.vo.GbInventoryPriceVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class GbInventoryPriceServiceImpl implements GbInventoryPriceService {

    @Autowired
    private ConfigInventoryLibMapper configInventoryLibMapper;
    @Autowired
    private ConfigInventoryChapterMapper configInventoryChapterMapper;
    @Autowired
    private InventoryPriceMapper inventoryPriceMapper;

    @Override
    public TableDataInfo selectConfigInventoryLibList(GbInventoryPriceVo vo) {
        String chapterId = vo.getChapterId();
        Long companyId = SecurityUtils.getCompanyId();
        if (StrUtil.isNotBlank(vo.getStartTime())) {
            vo.setStartTime(vo.getStartTime() + "-01");
        }
        if (StrUtil.isNotBlank(vo.getEndTime())) {
            int totalDaysOfMonth = DateUtil.getTotalDaysOfMonth(DateUtil.getDate(vo.getEndTime()));
            vo.setEndTime(vo.getEndTime() + "-" + totalDaysOfMonth);
        }
        ConfigInventoryLib lib = new ConfigInventoryLib();
        lib.setCompanyId(companyId);
        lib.setListNorm(vo.getListNorm());
        lib.setType(vo.getType());
        lib.setListCoding(vo.getListCoding());
        lib.setListName(vo.getListName());
        List<ConfigInventoryLib> configInventoryLibs = new ArrayList<>();
        if (StrUtil.isEmpty(chapterId) || StrUtil.equals(chapterId, CommonConstants.DEF_PID)) {
            PageUtils.startPage();
            configInventoryLibs = configInventoryLibMapper.selectConfigInventoryLibList(lib, null);
        } else {
            List<String> chapterIds = new ArrayList<>();
            chapterIds.add(chapterId);
            List<ConfigInventoryChapter> children = configInventoryChapterMapper.selectChildById(chapterId,companyId);
            if (CollUtil.isNotEmpty(children)) {
                for (ConfigInventoryChapter child : children) {
                    chapterIds.add(child.getId());
                }
            }
            PageUtils.startPage();
            configInventoryLibs = configInventoryLibMapper.selectConfigInventoryLibList(lib, chapterIds);
        }

        if (CollUtil.isEmpty(configInventoryLibs)) {
            return new TableDataInfo();
        }

        long total = new PageInfo(configInventoryLibs).getTotal();

        List<String> listCodes = configInventoryLibs.stream().map(ConfigInventoryLib::getListCoding).collect(Collectors.toList());

        ListValueMap<String,InventoryPriceBo> priceBoList = new ListValueMap<>();

        List<InventoryPriceBo> detailPriceBo = this.getDetailPriceBo(vo, listCodes);
        Map<String, List<InventoryPriceBo>> collect = detailPriceBo.stream().collect(Collectors.groupingBy(InventoryPriceBo::getListCode));
        Set<String> bqItemCodes = collect.keySet();
        for (String listCode : listCodes) {
            for (String bqItemCode : bqItemCodes) {
                if (bqItemCode.startsWith(listCode)) {
                    List<InventoryPriceBo> inventoryPriceBos = collect.get(bqItemCode);
                    for (InventoryPriceBo inventoryPriceBo : inventoryPriceBos) {
                        priceBoList.putValue(listCode,inventoryPriceBo);
                    }
                }
            }
        }


        List<GbInventoryPriceBo> res = new ArrayList<>();
        for (ConfigInventoryLib configInventoryLib : configInventoryLibs) {
            String listCoding = configInventoryLib.getListCoding();
            GbInventoryPriceBo convert = GbInventoryPriceBo.convert(configInventoryLib);
            List<InventoryPriceBo> inventoryPriceBos = priceBoList.get(listCoding);
            if (CollUtil.isNotEmpty(inventoryPriceBos)) {
                setPriceDetail(convert,inventoryPriceBos);
            }
            res.add(convert);
        }

        return new TableDataInfo(res, Convert.toInt(total));
    }

    @Override
    public List<InventoryPriceBo> detailPriceList(GbInventoryPriceVo vo) {

        return getDetailPriceBo(vo, null);
    }

    @Override
    public GbInventoryPriceBo getMMADetail(GbInventoryPriceVo vo) {
        List<InventoryPriceBo> detailPriceBo = getDetailPriceBo(vo, null);
        GbInventoryPriceBo bo = new GbInventoryPriceBo();
        setPriceDetail(bo,detailPriceBo);
        return bo;
    }

    @Override
    public List<GbInventoryPriceBo> selectConfigInventoryLibListNoPage(GbInventoryPriceVo vo) {
        String chapterId = vo.getChapterId();
        Long companyId = SecurityUtils.getCompanyId();
        if (StrUtil.isNotBlank(vo.getStartTime())) {
            vo.setStartTime(vo.getStartTime() + "-01");
        }
        if (StrUtil.isNotBlank(vo.getEndTime())) {
            int totalDaysOfMonth = DateUtil.getTotalDaysOfMonth(DateUtil.getDate(vo.getEndTime()));
            vo.setEndTime(vo.getEndTime() + "-" + totalDaysOfMonth);
        }
        ConfigInventoryLib lib = new ConfigInventoryLib();
        lib.setCompanyId(companyId);
        lib.setListNorm(vo.getListNorm());
        lib.setType(vo.getType());
        List<ConfigInventoryLib> configInventoryLibs = new ArrayList<>();
        if (StrUtil.isEmpty(chapterId) || StrUtil.equals(chapterId, CommonConstants.DEF_PID)) {
            configInventoryLibs = configInventoryLibMapper.selectConfigInventoryLibList(lib, null);
        } else {
            List<String> chapterIds = new ArrayList<>();
            chapterIds.add(chapterId);
            List<ConfigInventoryChapter> children = configInventoryChapterMapper.selectChildById(chapterId,companyId);
            if (CollUtil.isNotEmpty(children)) {
                for (ConfigInventoryChapter child : children) {
                    chapterIds.add(child.getId());
                }
            }
            configInventoryLibs = configInventoryLibMapper.selectConfigInventoryLibList(lib, chapterIds);
        }

        long total = new PageInfo(configInventoryLibs).getTotal();

        List<String> listCodes = configInventoryLibs.stream().map(ConfigInventoryLib::getListCoding).collect(Collectors.toList());

        ListValueMap<String,InventoryPriceBo> priceBoList = new ListValueMap<>();

        List<InventoryPriceBo> detailPriceBo = this.getDetailPriceBo(vo, listCodes);
        Map<String, List<InventoryPriceBo>> collect = detailPriceBo.stream().collect(Collectors.groupingBy(InventoryPriceBo::getListCode));
        Set<String> bqItemCodes = collect.keySet();
        for (String listCode : listCodes) {
            for (String bqItemCode : bqItemCodes) {
                if (bqItemCode.startsWith(listCode)) {
                    List<InventoryPriceBo> inventoryPriceBos = collect.get(bqItemCode);
                    for (InventoryPriceBo inventoryPriceBo : inventoryPriceBos) {
                        priceBoList.putValue(listCode,inventoryPriceBo);
                    }
                }
            }
        }

        List<GbInventoryPriceBo> res = new ArrayList<>();
        for (ConfigInventoryLib configInventoryLib : configInventoryLibs) {
            String listCoding = configInventoryLib.getListCoding();
            GbInventoryPriceBo convert = GbInventoryPriceBo.convert(configInventoryLib);
            List<InventoryPriceBo> inventoryPriceBos = priceBoList.get(listCoding);
            if (CollUtil.isNotEmpty(inventoryPriceBos)) {
                setPriceDetail(convert,inventoryPriceBos);
            }
            res.add(convert);
        }
        return res;
    }

    private void setPriceDetail(GbInventoryPriceBo convert, List<InventoryPriceBo> inventoryPriceBos) {
        Optional<Date> maxDateTime = inventoryPriceBos.stream().map(InventoryPriceBo::getCreateTime).max(Date::compareTo);
        Optional<Date> minDateTime = inventoryPriceBos.stream().map(InventoryPriceBo::getCreateTime).min(Date::compareTo);

        Optional<BigDecimal> maxPrice = inventoryPriceBos.stream().map(InventoryPriceBo::getPrice).max(BigDecimal::compareTo);
        Optional<BigDecimal> minPrice = inventoryPriceBos.stream().map(InventoryPriceBo::getPrice).min(BigDecimal::compareTo);

        OptionalDouble average = inventoryPriceBos.stream().map(InventoryPriceBo::getPrice).mapToDouble(BigDecimal::doubleValue).average();
        convert.setQdAmount(inventoryPriceBos.size());
        convert.setAvgPrice(Convert.toStr(average.isPresent() ? NumberUtil.getRoundedTY(average.getAsDouble()) : NumberUtil.getRoundedTY(BigDecimal.ZERO)));
        convert.setPriceRange(
                Convert.toStr( minPrice.isPresent() ? NumberUtil.getRoundedTY( minPrice.get() ) : NumberUtil.getRoundedTY(BigDecimal.ZERO) ) + "~" +
                Convert.toStr( maxPrice.isPresent() ? NumberUtil.getRoundedTY( maxPrice.get() ) : NumberUtil.getRoundedTY(BigDecimal.ZERO) )
        );

        convert.setMinPrice(Convert.toStr( minPrice.isPresent() ? NumberUtil.getRoundedTY( minPrice.get() ) : NumberUtil.getRoundedTY(BigDecimal.ZERO) ));
        convert.setMaxPrice(Convert.toStr( maxPrice.isPresent() ? NumberUtil.getRoundedTY( maxPrice.get() ) : NumberUtil.getRoundedTY(BigDecimal.ZERO) ));

        convert.setTimeRange(
                (minDateTime.map(DateUtil::dateToyMd).orElse("无"))  + "~" +
                (maxDateTime.map(DateUtil::dateToyMd).orElse("无"))
        );
    }

    private List<InventoryPriceBo> getDetailPriceBo(GbInventoryPriceVo vo,List<String> listCodes) {
        List<InventoryPriceBo> inventoryPriceBos = inventoryPriceMapper.selectPriceByCodeAndOther(vo, listCodes);
        for (InventoryPriceBo inventoryPriceBo : inventoryPriceBos) {
            BigDecimal price = inventoryPriceBo.getPrice();
            inventoryPriceBo.setPrice(NumberUtil.getRoundedTY(price));
        }
        return inventoryPriceBos;
    }

}
